﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Windows.Forms;
using System.Xml.Schema;
using System.IO;
using AirProperties.Resources;

namespace AirProperties
{
    //Air Application Properties Manager
    class PropertyManager
    {
        private static XmlDocument moAapDoc;
        private static XmlNamespaceManager moNamespaceMgr;
        private static XmlNode moRoot;
        private static Boolean mbIsInitialised;
        private static Exception moLastExpception;
        private static AIRVersion meMajorAirVersion;
        private const String BASE_AIR_NAMESPACE = "http://ns.adobe.com/air/application/";

        public enum AIRVersion
        {
            V10 = 0, //version 1.0
            V11 = 1, //version 1.1
            V15 = 2, //version 1.5
            V153 = 3,//version 1.5.3
            V20      //version 2.0+
        }

        public static Exception LastException
        {
            get
            {
                return moLastExpception;
            }
        }

        public static Boolean IsInitialised
        {
            get
            {
                return mbIsInitialised;
            }
        }

        public static AIRVersion MajorVersion
        {
            get
            {
                return meMajorAirVersion;
            }
        }

        public static Boolean InitializeProperties(string psFilePath)
        {
            Boolean lbResult = false;

            try
            {
                moAapDoc = new XmlDocument();
                moAapDoc.Load(psFilePath);

                moRoot = moAapDoc.DocumentElement;

                //determine if valid descriptor file, and which version of AIR is specified
                if (!moRoot.NamespaceURI.ToLower().StartsWith(BASE_AIR_NAMESPACE))
                {
                    throw new Exception(String.Format(LocaleHelper.GetString("Exception.Message.NotAirDescriptorFile"), psFilePath));
                }
                else
                {
                    if (moRoot.NamespaceURI.ToLower().StartsWith(BASE_AIR_NAMESPACE + "1.0"))
                        meMajorAirVersion = AIRVersion.V10;
                    else if (moRoot.NamespaceURI.ToLower().StartsWith(BASE_AIR_NAMESPACE + "1.1"))
                        meMajorAirVersion = AIRVersion.V11;
                    else if (moRoot.NamespaceURI.ToLower().StartsWith(BASE_AIR_NAMESPACE + "1.5.3"))
                        meMajorAirVersion = AIRVersion.V153;
                    else if (moRoot.NamespaceURI.ToLower().StartsWith(BASE_AIR_NAMESPACE + "1.5"))
                        meMajorAirVersion = AIRVersion.V15;
                    else if (moRoot.NamespaceURI.ToLower().StartsWith(BASE_AIR_NAMESPACE + "2"))
                        meMajorAirVersion = AIRVersion.V20;
                    else
                        throw new Exception(String.Format(LocaleHelper.GetString("Exception.Message.NotAirDescriptorFile"), psFilePath));
                }

                moNamespaceMgr = new XmlNamespaceManager(moAapDoc.NameTable);
                moNamespaceMgr.AddNamespace("air", moRoot.NamespaceURI);

                lbResult = true;
            }
            catch (Exception ex)
            {
                moLastExpception = ex;
            }
            finally
            {
                //nothing to clean up
            }

            mbIsInitialised = lbResult;
            return lbResult;
        }

        public static Boolean CommitProperties(string psFilePath)
        {
            Boolean lbResult = false;

            try
            {
                moAapDoc.Save(psFilePath);
                lbResult = true;
            }
            catch (Exception ex)
            {
                moLastExpception = ex;
            }
            finally
            {
                //nothing to clean up
            }

            mbIsInitialised = lbResult;
            return lbResult;
        }

        public static void GetAttribute(string psAttribute, TextBox poTextBox)
        {
            XmlNode loPropertyNode;

            loPropertyNode = moRoot.Attributes.GetNamedItem(psAttribute);
            if (loPropertyNode != null)
                poTextBox.Text = loPropertyNode.InnerText.Trim();
            else
                poTextBox.Text = "";
        }

        public static String GetAttribute(string psAttribute)
        {
            XmlNode loPropertyNode;

            loPropertyNode = moRoot.Attributes.GetNamedItem(psAttribute);
            if (loPropertyNode != null)
                return loPropertyNode.InnerText.Trim();
            else
                return "";
        }

        public static void SetAttribute(string psAttribute, TextBox poTextBox)
        {
            XmlNode loPropertyNode;
            XmlAttribute loAttributeNode;

            loPropertyNode = moRoot.Attributes.GetNamedItem(psAttribute);

            if (loPropertyNode != null)
            {
                if (poTextBox.Text != "")
                {
                    loPropertyNode.InnerText = poTextBox.Text;
                }
                else
                {
                    //remove the attribute, reverting to system default
                    moRoot.Attributes.RemoveNamedItem(psAttribute);
                }
            }
            else
            {
                //only add attribute if there is a value to add
                if (poTextBox.Text != "")
                {
                    loAttributeNode = moAapDoc.CreateAttribute(psAttribute);
                    loAttributeNode.Value = poTextBox.Text;
                    moRoot.Attributes.Append(loAttributeNode);
                }
            }
        }

        public static String GetProperty(string psProperty)
        {
            XmlNode loPropertyNode;

            loPropertyNode = moRoot.SelectSingleNode("air:" + psProperty.Replace("/", "/air:"), moNamespaceMgr);
            if (loPropertyNode != null)
                return loPropertyNode.InnerText.Trim();
            else
                return "";
        }

        private static String GetProperty(string psProperty, XmlNode psRootNode)
        {
            XmlNode loPropertyNode;

            loPropertyNode = psRootNode.SelectSingleNode("air:" + psProperty.Replace("/", "/air:"), moNamespaceMgr);
            if (loPropertyNode != null)
                return loPropertyNode.InnerText.Trim();
            else
                return "";
        }

        public static void GetProperty(string psProperty, TextBox poTextBox)
        {
            GetProperty(psProperty, poTextBox, String.Empty);
        }

        public static void GetProperty(string psProperty, TextBox poTextBox, string psLocale)
        {
            XmlNode loPropertyNode;
            XmlNode loLocaleNode;


            loPropertyNode = moRoot.SelectSingleNode("air:" + psProperty.Replace("/", "/air:"), moNamespaceMgr);
            if (loPropertyNode != null)
            {
                if (psLocale != String.Empty && loPropertyNode.HasChildNodes)
                {
                    foreach (XmlNode loChildNode in loPropertyNode.ChildNodes)
                    {
                        if (loChildNode.Attributes != null)
                        {
                            loLocaleNode = loChildNode.Attributes.GetNamedItem("xml:lang");
                            if (loLocaleNode != null)
                            {
                                if (loLocaleNode.InnerText.Equals(psLocale))
                                {
                                    poTextBox.Text = loChildNode.InnerText.Trim();
                                    break;
                                }
                                else
                                {
                                    poTextBox.Text = "";
                                }
                            }
                        }
                        else
                        {
                            poTextBox.Text = "";
                        }
                    }
                }
                else if (loPropertyNode.ChildNodes.Count > 1)
                {
                    poTextBox.Text = loPropertyNode.FirstChild.InnerText.Trim();
                }
                else
                    poTextBox.Text = loPropertyNode.InnerText.Trim();
            }
            else
                poTextBox.Text = "";
        }

        public static void GetProperty(string psProperty, CheckBox poCheckBox)
        {
            XmlNode loPropertyNode;

            loPropertyNode = moRoot.SelectSingleNode("air:" + psProperty.Replace("/", "/air:"), moNamespaceMgr);
            if (loPropertyNode != null)
            {
                if (loPropertyNode.InnerText.ToLower() == "true")
                    poCheckBox.Checked = true;
                else
                    poCheckBox.Checked = false;
            }
            else
                poCheckBox.CheckState = CheckState.Indeterminate;
        }

        public static void GetProperty(string psProperty, ComboBox poComboBox, int piDefaultIndex)
        {
            XmlNode loPropertyNode;
            Boolean lbFoundListItem = false;

            loPropertyNode = moRoot.SelectSingleNode("air:" + psProperty.Replace("/", "/air:"), moNamespaceMgr);
            if (loPropertyNode != null)
            {
                foreach (ListItem loListItem in poComboBox.Items)
                {
                    if (loListItem.Value == loPropertyNode.InnerText.Trim().ToLower())
                    {
                        poComboBox.SelectedItem = loListItem;
                        lbFoundListItem = true;
                    }
                }
                if (!lbFoundListItem)
                    poComboBox.SelectedIndex = piDefaultIndex;
            }
            else
                poComboBox.SelectedIndex = piDefaultIndex;
        }

        public static void SetProperty(string psProperty, string psValue)
        {
            XmlNode loPropertyNode;
            String lsChildName;
            int index;

            loPropertyNode = moRoot.SelectSingleNode("air:" + psProperty.Replace("/", "/air:"), moNamespaceMgr);
            if (loPropertyNode != null)
            {
                if (psValue != "")
                {
                    loPropertyNode.InnerText = psValue;
                }
                else
                {
                    //remove the node, reverting to system default
                    GetParentNode(psProperty).RemoveChild(loPropertyNode);
                }
            }
            else
            {
                //only add property if there is a value to add
                if (psValue != "")
                {
                    index = psProperty.IndexOf('/');
                    lsChildName = psProperty.Substring(index + 1, psProperty.Length - (index + 1));
                    loPropertyNode = moAapDoc.CreateNode(XmlNodeType.Element, lsChildName, moNamespaceMgr.LookupNamespace("air"));
                    if (loPropertyNode != null)
                    {
                        loPropertyNode.InnerText = psValue;
                        GetParentNode(psProperty).AppendChild(loPropertyNode);
                    }
                }
            }
        }

        public static void SetProperty(string psProperty, TextBox poTextBox)
        {
            XmlNode loPropertyNode;
            String lsChildName;
            int index;

            loPropertyNode = moRoot.SelectSingleNode("air:" + psProperty.Replace("/", "/air:"), moNamespaceMgr);

            if (loPropertyNode != null)
            {
                if (poTextBox.Text != "")
                {
                    loPropertyNode.InnerText = poTextBox.Text;
                }
                else
                {
                    //remove the node, reverting to system default
                    GetParentNode(psProperty).RemoveChild(loPropertyNode);
                }
            }
            else
            {
                //only add property if there is a value to add
                if (poTextBox.Text != "")
                {
                    index = psProperty.IndexOf('/');
                    lsChildName = psProperty.Substring(index + 1, psProperty.Length - (index + 1));
                    loPropertyNode = moAapDoc.CreateNode(XmlNodeType.Element, lsChildName, moNamespaceMgr.LookupNamespace("air"));
                    if (loPropertyNode != null)
                    {
                        loPropertyNode.InnerText = poTextBox.Text;
                        GetParentNode(psProperty).AppendChild(loPropertyNode);
                    }
                }
            }
        }

        //Searches the specified property node for an element with the specified locale, creating one if none is found. 
        //Supplied element parameter is referenced to resulting element.
        //Returns true if the element already existed, false if it was created.
        private static Boolean GetLocalizedElement(XmlNode poPropertyNode, String psLocale, ref XmlElement poLocaleElement)
        {
            Boolean lbFound = false;
            XmlNode loLocaleAttribute;
            XmlElement loLocaleElement = null;

            if (psLocale != String.Empty)
            {
                if (poPropertyNode.HasChildNodes)
                {
                    foreach (XmlNode loChildNode in poPropertyNode.ChildNodes)
                    {
                        if (loChildNode.Attributes != null)
                        {
                            loLocaleAttribute = loChildNode.Attributes.GetNamedItem("xml:lang");
                            if (loLocaleAttribute != null)
                            {
                                if (loLocaleAttribute.InnerText.Equals(psLocale))
                                {
                                    loLocaleElement = (XmlElement)loChildNode;
                                    lbFound = true;
                                    break;
                                }
                            }
                        }
                    }
                }
                if (!lbFound)
                {
                    loLocaleElement = moAapDoc.CreateElement("text", moNamespaceMgr.LookupNamespace("air"));
                    loLocaleElement.SetAttribute("xml:lang", psLocale);
                }
                poLocaleElement = loLocaleElement;
            }
            return lbFound;
        }

        public static void SetProperty(string psProperty, TextBox poTextBox, String psLocale)
        {
            SetProperty(psProperty, poTextBox, psLocale, false);
        }

        public static void SetProperty(string psProperty, TextBox poTextBox, String psLocale, Boolean pbIsDefaultLocale)
        {
            XmlNode loPropertyNode;
            XmlElement loLocaleElement = null;
            Boolean lbElementExists;
            String lsChildName;
            int index;

            //if no locale then just add/edit the node
            if (psLocale == String.Empty)
            {
                SetProperty(psProperty, poTextBox);
                return;
            }

            loPropertyNode = moRoot.SelectSingleNode("air:" + psProperty.Replace("/", "/air:"), moNamespaceMgr);

            if (loPropertyNode != null)
            {
                lbElementExists = GetLocalizedElement(loPropertyNode, psLocale, ref loLocaleElement);
                loLocaleElement.InnerText = poTextBox.Text;
                if (!lbElementExists)
                {
                    //remove any existing non-localised values
                    if (loPropertyNode.HasChildNodes && loPropertyNode.FirstChild.NodeType == XmlNodeType.Text)
                    {
                        loPropertyNode.InnerText = "";
                    }
                    if (pbIsDefaultLocale)
                    {
                        //if default locale, then element has to be first child
                        loPropertyNode.PrependChild(loLocaleElement);
                    }
                    else
                    {
                        loPropertyNode.AppendChild(loLocaleElement);
                    }
                }
                else
                {
                    //if default locale and element isn't the first child then move it
                    if (pbIsDefaultLocale && loLocaleElement != loPropertyNode.FirstChild)
                    {
                        loPropertyNode.RemoveChild(loLocaleElement);
                        loPropertyNode.PrependChild(loLocaleElement);
                    }
                }
            }
            else
            {
                //only add property if there is a value to add
                if (poTextBox.Text != "")
                {
                    index = psProperty.IndexOf('/');
                    lsChildName = psProperty.Substring(index + 1, psProperty.Length - (index + 1));
                    loPropertyNode = moAapDoc.CreateNode(XmlNodeType.Element, lsChildName, moNamespaceMgr.LookupNamespace("air"));
                    if (loPropertyNode != null)
                    {
                        GetLocalizedElement(loPropertyNode, psLocale, ref loLocaleElement);
                        loLocaleElement.InnerText = poTextBox.Text;
                        loPropertyNode.AppendChild(loLocaleElement);
                        GetParentNode(psProperty).AppendChild(loPropertyNode);
                    }
                }
            }
        }

        public static void SetProperty(string psProperty, CheckBox poCheckBox)
        {
            XmlNode loPropertyNode;
            String lsChildName;
            int index;

            loPropertyNode = moRoot.SelectSingleNode("air:" + psProperty.Replace("/", "/air:"), moNamespaceMgr);
            if (loPropertyNode != null)
            {
                if (poCheckBox.CheckState != CheckState.Indeterminate)
                {
                    loPropertyNode.InnerText = poCheckBox.Checked.ToString().ToLower();
                }
                else
                {
                    //remove the node, reverting to system default
                    GetParentNode(psProperty).RemoveChild(loPropertyNode);
                }
            }
            else
            {
                //only add property if there is a value to add
                if (poCheckBox.CheckState != CheckState.Indeterminate)
                {
                    index = psProperty.IndexOf('/');
                    lsChildName = psProperty.Substring(index + 1, psProperty.Length - (index + 1));
                    loPropertyNode = moAapDoc.CreateNode(XmlNodeType.Element, lsChildName, moNamespaceMgr.LookupNamespace("air"));
                    if (loPropertyNode != null)
                    {
                        loPropertyNode.InnerText = poCheckBox.Checked.ToString().ToLower();
                        GetParentNode(psProperty).AppendChild(loPropertyNode);
                    }
                }
            }
        }

        public static void SetProperty(string psProperty, ComboBox poComboBox)
        {
            XmlNode loPropertyNode;
            ListItem loSelectedItem;
            String lsChildName;
            int index;

            loSelectedItem = (ListItem)poComboBox.SelectedItem;
            if (loSelectedItem != null)
            {
                loPropertyNode = moRoot.SelectSingleNode("air:" + psProperty.Replace("/", "/air:"), moNamespaceMgr);
                if (loPropertyNode != null)
                    loPropertyNode.InnerText = loSelectedItem.Value;
                else
                {
                    index = psProperty.IndexOf('/');
                    lsChildName = psProperty.Substring(index + 1, psProperty.Length - (index + 1));
                    loPropertyNode = moAapDoc.CreateNode(XmlNodeType.Element, lsChildName, moNamespaceMgr.LookupNamespace("air"));
                    if (loPropertyNode != null)
                    {
                        loPropertyNode.InnerText = loSelectedItem.Value;
                        GetParentNode(psProperty).AppendChild(loPropertyNode);
                    }
                }
            }
        }

        public static void RemoveLocalizedProperty(string psProperty, String psLocale)
        {
            XmlNode loPropertyNode;
            XmlElement loLocaleElement = null;
            Boolean lbElementExists;

            loPropertyNode = moRoot.SelectSingleNode("air:" + psProperty.Replace("/", "/air:"), moNamespaceMgr);

            if (loPropertyNode != null)
            {
                lbElementExists = GetLocalizedElement(loPropertyNode, psLocale, ref loLocaleElement);

                if (lbElementExists)
                {
                    loPropertyNode.RemoveChild(loLocaleElement);
                }
            }
        }

        public static void CreateLocalizedProperty(string psProperty, String psLocale, Boolean pbIsDefaultLocale)
        {
            XmlNode loPropertyNode;
            XmlElement loLocaleElement = null;
            Boolean lbElementExists;
            String lsChildName;
            int index;

            loPropertyNode = moRoot.SelectSingleNode("air:" + psProperty.Replace("/", "/air:"), moNamespaceMgr);

            if (loPropertyNode != null)
            {
                lbElementExists = GetLocalizedElement(loPropertyNode, psLocale, ref loLocaleElement);
                loLocaleElement.InnerText = String.Empty;
                if (!lbElementExists)
                {
                    //if there is any existing non-localised values, copy them to the localised element (will only occur for first localised element)
                    if (loPropertyNode.HasChildNodes && loPropertyNode.FirstChild.NodeType == XmlNodeType.Text)
                    {
                        loLocaleElement.InnerText = loPropertyNode.InnerText;
                        loPropertyNode.InnerText = "";
                    }
                    if (pbIsDefaultLocale)
                    {
                        //if default locale, then element has to be first child
                        loPropertyNode.PrependChild(loLocaleElement);
                    }
                    else
                    {
                        loPropertyNode.AppendChild(loLocaleElement);
                    }
                }
                else
                {
                    //should never get here as we are supposed to be creating new element, but cater for it anyways
                    //if default locale and element isn't the first child then move it
                    if (pbIsDefaultLocale && loLocaleElement != loPropertyNode.FirstChild)
                    {
                        loPropertyNode.RemoveChild(loLocaleElement);
                        loPropertyNode.PrependChild(loLocaleElement);
                    }
                }
            }
            else
            {
                index = psProperty.IndexOf('/');
                lsChildName = psProperty.Substring(index + 1, psProperty.Length - (index + 1));
                loPropertyNode = moAapDoc.CreateNode(XmlNodeType.Element, lsChildName, moNamespaceMgr.LookupNamespace("air"));
                if (loPropertyNode != null)
                {
                    GetLocalizedElement(loPropertyNode, psLocale, ref loLocaleElement);
                    loLocaleElement.InnerText = String.Empty;
                    loPropertyNode.AppendChild(loLocaleElement);
                    GetParentNode(psProperty).AppendChild(loPropertyNode);
                }
            }
        }

        /* Simple method returns the parent node based on the supplied property name (XPATH)
         * If parent node does not exist it is created and added to the root element
         * This function will only work for a single parent/child, but that is all
         * that is required at this point as only element in AIR properties file that has more
         * than two levels is fileTypes which is handled by the Get/SetFileTypes methods.
         **/
        private static XmlNode GetParentNode(string psProperty)
        {
            XmlNode loParentNode;
            String lsParentName;
            int index;

            index = psProperty.IndexOf('/');

            if (index == -1)
            {
                return moRoot;
            }
            else
            {
                lsParentName = psProperty.Substring(0, index);
                loParentNode = moRoot.SelectSingleNode("air:" + lsParentName, moNamespaceMgr);
                if (loParentNode == null)
                {
                    loParentNode = moAapDoc.CreateNode(XmlNodeType.Element, lsParentName, moNamespaceMgr.LookupNamespace("air"));
                    moRoot.AppendChild(loParentNode);
                }
                return loParentNode;
            }
        }

        public static void GetPropertyLocales(string psProperty, List<string> poLocales)
        {
            XmlNode loPropertyNode;
            XmlNode loLocaleNode;

            loPropertyNode = moRoot.SelectSingleNode("air:" + psProperty.Replace("/", "/air:"), moNamespaceMgr);
            if (loPropertyNode != null && loPropertyNode.HasChildNodes)
            {
                foreach (XmlNode loChildNode in loPropertyNode.ChildNodes)
                {
                    if (loChildNode.Attributes != null)
                    {
                        loLocaleNode = loChildNode.Attributes.GetNamedItem("xml:lang");
                        if (loLocaleNode != null)
                        {
                            if (!poLocales.Contains(loLocaleNode.InnerText))
                            {
                                poLocales.Add(loLocaleNode.InnerText);
                            }
                        }
                    }
                }
            }
        }

        //OK, this method puts the responsibility of searching
        //for property names within the Property Manager. The key reason for
        //this is that is a lot easier from the UI's perspective to work with a 
        //collection of 'fileType' business objects rather than straight XML
        public static void GetFileTypes(List<AirFileType> poFileTypes)
        {
            XmlNode loPropertyNode;
            AirFileType loFileType;

            poFileTypes.Clear();

            loPropertyNode = moRoot.SelectSingleNode("air:fileTypes", moNamespaceMgr);
            if (loPropertyNode != null && loPropertyNode.HasChildNodes)
            {
                //loop through collection of xml fileType nodes
                foreach (XmlNode loChildNode in loPropertyNode.ChildNodes)
                {
                    //create a new fileType business object
                    loFileType = new AirFileType();
                    loFileType.Name = GetProperty("name", loChildNode);
                    loFileType.Extension = GetProperty("extension", loChildNode);
                    loFileType.Description = GetProperty("description", loChildNode);
                    loFileType.ContentType = GetProperty("contentType", loChildNode);
                    loFileType.Icon16 = GetProperty("icon/image16x16", loChildNode);
                    loFileType.Icon32 = GetProperty("icon/image32x32", loChildNode);
                    loFileType.Icon48 = GetProperty("icon/image48x48", loChildNode);
                    loFileType.Icon128 = GetProperty("icon/image128x128", loChildNode);
                    //add to the business object collection
                    poFileTypes.Add(loFileType);
                }
            }
        }

        //writes the collection of AirFileType objects to the fileTypes element in
        //the descriptor file. Again this takes the responsibility of property names
        //away from the UI, but that's the way it is.
        public static void SetFileTypes(List<AirFileType> poFileTypes)
        {
            XmlNode loFileTypesNode;
            XmlNode loFileTypeNode;

            //get fileTypes node
            loFileTypesNode = moRoot.SelectSingleNode("air:fileTypes", moNamespaceMgr);
            if (loFileTypesNode == null)
            {
                loFileTypesNode = moAapDoc.CreateNode(XmlNodeType.Element, "fileTypes", moNamespaceMgr.LookupNamespace("air"));
            }
            else
            {
                moRoot.RemoveChild(loFileTypesNode);
            }

            if (poFileTypes.Count <= 0)
            {
                return;
            }

            if (loFileTypesNode != null)
            {
                //clear contents
                loFileTypesNode.InnerText = "";

                //loop through collection of AirFileType 
                foreach (AirFileType loAirFileType in poFileTypes)
                {
                    //create a new fileType node
                    loFileTypeNode = moAapDoc.CreateNode(XmlNodeType.Element, "fileType", moNamespaceMgr.LookupNamespace("air"));

                    if (loFileTypeNode != null)
                    {
                        CreateChildNode(loFileTypeNode, "name", loAirFileType.Name);
                        CreateChildNode(loFileTypeNode, "extension", loAirFileType.Extension);
                        CreateChildNode(loFileTypeNode, "description", loAirFileType.Description);
                        CreateChildNode(loFileTypeNode, "contentType", loAirFileType.ContentType);
                        CreateChildNode(loFileTypeNode, "icon/image16x16", loAirFileType.Icon16);
                        CreateChildNode(loFileTypeNode, "icon/image32x32", loAirFileType.Icon32);
                        CreateChildNode(loFileTypeNode, "icon/image48x48", loAirFileType.Icon48);
                        CreateChildNode(loFileTypeNode, "icon/image128x128", loAirFileType.Icon128);
                    }
                    loFileTypesNode.AppendChild(loFileTypeNode);
                }

                //add the fileTypes node
                moRoot.AppendChild(loFileTypesNode);
            }
        }

        //Creates a child node on the specified parent node, will also create sub-parent node (used for creating fileType properties)
        private static void CreateChildNode(XmlNode poParentNode, String psChildNodeName, String psChildNodeValue)
        {
            XmlNode loParentNode;
            XmlNode loChildNode;
            String lsSubParentName;
            String lsChildName;
            int index;

            if (psChildNodeValue == String.Empty)
                return;

            //determine if there is a sub parent
            index = psChildNodeName.IndexOf('/');
            if (index == -1)
            {
                loParentNode = poParentNode;
            }
            else
            {
                //create a sub parent element if required
                lsSubParentName = psChildNodeName.Substring(0, index);
                loParentNode = poParentNode.SelectSingleNode("air:" + lsSubParentName, moNamespaceMgr);
                if (loParentNode == null)
                {
                    loParentNode = moAapDoc.CreateNode(XmlNodeType.Element, lsSubParentName, moNamespaceMgr.LookupNamespace("air"));
                    if (loParentNode != null)
                    {
                        poParentNode.AppendChild(loParentNode);
                    }
                }
            }

            lsChildName = psChildNodeName.Substring(index + 1, psChildNodeName.Length - (index + 1));
            loChildNode = moAapDoc.CreateNode(XmlNodeType.Element, lsChildName, moNamespaceMgr.LookupNamespace("air"));

            if (loChildNode != null)
            {
                loChildNode.InnerText = psChildNodeValue;
                loParentNode.AppendChild(loChildNode);
            }

        }


        //Simple class to constuct an Air Application File Type
        //The class requires external validation of property values.
        public class AirFileType
        {

            private String msName;
            private String msExtension;
            private String msDescription;
            private String msContentType;
            private String msIcon16;
            private String msIcon32;
            private String msIcon48;
            private String msIcon128;

            private Boolean mbNameIsValid;
            private Boolean mbExtensionIsValid;
            private Boolean mbDescriptionIsValid;
            private Boolean mbContentTypeIsValid;
            private Boolean mbIcon16IsValid;
            private Boolean mbIcon32IsValid;
            private Boolean mbIcon48IsValid;
            private Boolean mbIcon128IsValid;

            public AirFileType()
            {
                msName = String.Empty;
                msExtension = String.Empty;
                msDescription = String.Empty;
                msContentType = String.Empty;
                msIcon16 = String.Empty;
                msIcon32 = String.Empty;
                msIcon48 = String.Empty;
                msIcon128 = String.Empty;
            }


            public String Name
            {
                get
                {
                    return msName;
                }
                set
                {
                    msName = value;
                }
            }

            public String Extension
            {
                get
                {
                    return msExtension;
                }
                set
                {
                    msExtension = value;
                }
            }

            public String Description
            {
                get
                {
                    return msDescription;
                }
                set
                {
                    msDescription = value;
                }
            }

            public String ContentType
            {
                get
                {
                    return msContentType;
                }
                set
                {
                    msContentType = value;
                }
            }

            public String Icon16
            {
                get
                {
                    return msIcon16;
                }
                set
                {
                    msIcon16 = value;
                }
            }

            public String Icon32
            {
                get
                {
                    return msIcon32;
                }
                set
                {
                    msIcon32 = value;
                }
            }

            public string Icon48
            {
                get
                {
                    return msIcon48;
                }
                set
                {
                    msIcon48 = value;
                }
            }

            public String Icon128
            {
                get
                {
                    return msIcon128;
                }
                set
                {
                    msIcon128 = value;
                }
            }

            public Boolean NameIsValid
            {
                get
                {
                    return mbNameIsValid;
                }
                set
                {
                    mbNameIsValid = value;
                }
            }

            public Boolean ExtensionIsValid
            {
                get
                {
                    return mbExtensionIsValid;
                }
                set
                {
                    mbExtensionIsValid = value;
                }
            }

            public Boolean DescriptionIsValid
            {
                get
                {
                    return mbDescriptionIsValid;
                }
                set
                {
                    mbDescriptionIsValid = value;
                }
            }

            public Boolean ContentTypeIsValid
            {
                get
                {
                    return mbContentTypeIsValid;
                }
                set
                {
                    mbContentTypeIsValid = value;
                }
            }

            public Boolean Icon16IsValid
            {
                get
                {
                    return mbIcon16IsValid;
                }
                set
                {
                    mbIcon16IsValid = value;
                }
            }

            public Boolean Icon32IsValid
            {
                get
                {
                    return mbIcon32IsValid;
                }
                set
                {
                    mbIcon32IsValid = value;
                }
            }

            public Boolean Icon48IsValid
            {
                get
                {
                    return mbIcon48IsValid;
                }
                set
                {
                    mbIcon48IsValid = value;
                }
            }

            public Boolean Icon128IsValid
            {
                get
                {
                    return mbIcon128IsValid;
                }
                set
                {
                    mbIcon128IsValid = value;
                }
            }

            public Boolean IsValid
            {
                get
                {
                    return mbNameIsValid &&
                            mbExtensionIsValid &&
                            mbDescriptionIsValid &&
                            mbContentTypeIsValid &&
                            mbIcon16IsValid &&
                            mbIcon32IsValid &&
                            mbIcon48IsValid &&
                            mbIcon128IsValid;
                }
            }
        }

    }

}
